home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / samba.idb / usr / samba / src / source / shmem.c.z / shmem.c
Encoding:
C/C++ Source or Header  |  1998-10-28  |  24.5 KB  |  875 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    Shared memory functions
  5.    Copyright (C) Erik Devriendt 1996-1998
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21. */
  22.  
  23. #include "includes.h"
  24.  
  25.  
  26. #ifdef FAST_SHARE_MODES
  27.  
  28.  
  29. extern int DEBUGLEVEL;
  30.  
  31.  
  32. #define SMB_SHM_MAGIC 0x53484100
  33. /* = "SHM" in hex */
  34.  
  35. #define SMB_SHM_VERSION 2
  36.  
  37. /* we need world read for smbstatus to function correctly */
  38. #ifdef SECURE_SHARE_MODES
  39. #define SHM_FILE_MODE 0600
  40. #else
  41. #define SHM_FILE_MODE 0644
  42. #endif
  43.  
  44. #define SHMEM_HASH_SIZE 113
  45.  
  46.  
  47. /* WARNING : offsets are used because mmap() does not guarantee that all processes have the 
  48.    shared memory mapped to the same address */
  49.  
  50. struct SmbShmHeader
  51. {
  52.    int smb_shm_magic;
  53.    int smb_shm_version;
  54.    int total_size;    /* in bytes */
  55.    BOOL consistent;
  56.    int first_free_off;
  57.    int userdef_off;    /* a userdefined offset. can be used to store root of tree or list */
  58.    struct {        /* a cell is a range of bytes of sizeof(struct SmbShmBlockDesc) size */
  59.       int cells_free;
  60.       int cells_used;
  61.       int cells_system; /* number of cells used as allocated block descriptors */
  62.    } statistics;
  63. };
  64.  
  65. #define SMB_SHM_NOT_FREE_OFF (-1)
  66. struct SmbShmBlockDesc
  67. {
  68.    int next;    /* offset of next block in the free list or SMB_SHM_NOT_FREE_OFF when block in use  */
  69.    int          size;   /* user size in BlockDescSize units */
  70. };
  71.  
  72. #define    EOList_Addr    (struct SmbShmBlockDesc *)( 0 )
  73. #define EOList_Off      0
  74.  
  75. #define    CellSize    sizeof(struct SmbShmBlockDesc)
  76.  
  77. /* HeaderSize aligned on 8 byte boundary */
  78. #define    AlignedHeaderSize      ((sizeof(struct SmbShmHeader)+7) & ~7)
  79.  
  80. static int  smb_shm_fd = -1;
  81. static pstring smb_shm_processreg_name = "";
  82.  
  83. static struct SmbShmHeader *smb_shm_header_p = (struct SmbShmHeader *)0;
  84. static int smb_shm_times_locked = 0;
  85.  
  86. static BOOL smb_shm_initialize_called = False;
  87.  
  88. static int read_only;
  89.  
  90. static BOOL smb_shm_global_lock(void)
  91. {
  92.    if (smb_shm_fd < 0)
  93.    {
  94.       DEBUG(0,("ERROR smb_shm_global_lock : bad smb_shm_fd (%d)\n",smb_shm_fd));
  95.       return False;
  96.    }
  97.    
  98.    smb_shm_times_locked++;
  99.    
  100.    if(smb_shm_times_locked > 1)
  101.    {
  102.       DEBUG(5,("smb_shm_global_lock : locked %d times\n",smb_shm_times_locked));
  103.       return True;
  104.    }
  105.  
  106.    if (read_only)
  107.        return True;
  108.    
  109.    /* Do an exclusive wait lock on the first byte of the file */
  110.    if (fcntl_lock(smb_shm_fd, F_SETLKW, 0, 1, F_WRLCK) == False)
  111.    {
  112.       DEBUG(0,("ERROR smb_shm_global_lock : fcntl_lock failed with code %s\n",strerror(errno)));
  113.       smb_shm_times_locked--;
  114.       return False;
  115.    }
  116.    
  117.    return True;
  118.    
  119. }
  120.  
  121. static BOOL smb_shm_global_unlock(void)
  122. {
  123.    if (smb_shm_fd < 0)
  124.    {
  125.       DEBUG(0,("ERROR smb_shm_global_unlock : bad smb_shm_fd (%d)\n",smb_shm_fd));
  126.       return False;
  127.    }
  128.    
  129.    if(smb_shm_times_locked == 0)
  130.    {
  131.       DEBUG(0,("ERROR smb_shm_global_unlock : shmem not locked\n"));
  132.       return False;
  133.    }
  134.    
  135.    smb_shm_times_locked--;
  136.    
  137.    if(smb_shm_times_locked > 0)
  138.    {
  139.       DEBUG(5,("smb_shm_global_unlock : still locked %d times\n",smb_shm_times_locked));
  140.       return True;
  141.    }
  142.  
  143.    if (read_only)
  144.        return True;
  145.    
  146.    /* Do a wait unlock on the first byte of the file */
  147.    if (fcntl_lock(smb_shm_fd, F_SETLKW, 0, 1, F_UNLCK) == False)
  148.    {
  149.       DEBUG(0,("ERROR smb_shm_global_unlock : fcntl_lock failed with code %s\n",strerror(errno)));
  150.       smb_shm_times_locked++;
  151.       return False;
  152.    }
  153.    
  154.    return True;
  155.    
  156. }
  157.  
  158.  
  159. static void *smb_shm_offset2addr(int offset)
  160. {
  161.    if (offset == 0 )
  162.       return (void *)(0);
  163.    
  164.    if (!smb_shm_header_p)
  165.       return (void *)(0);
  166.    
  167.    return (void *)((char *)smb_shm_header_p + offset );
  168. }
  169.  
  170. static int smb_shm_addr2offset(void *addr)
  171. {
  172.    if (!addr)
  173.       return 0;
  174.    
  175.    if (!smb_shm_header_p)
  176.       return 0;
  177.    
  178.    return (int)((char *)addr - (char *)smb_shm_header_p);
  179. }
  180.  
  181.  
  182.  
  183. static int smb_shm_alloc(int size)
  184. {
  185.    unsigned num_cells ;
  186.    struct SmbShmBlockDesc *scanner_p;
  187.    struct SmbShmBlockDesc *prev_p;
  188.    struct SmbShmBlockDesc *new_p;
  189.    int result_offset;
  190.    
  191.    
  192.    if( !smb_shm_header_p )
  193.    {
  194.       /* not mapped yet */
  195.       DEBUG(0,("ERROR smb_shm_alloc : shmem not mapped\n"));
  196.       return 0;
  197.    }
  198.    
  199.    smb_shm_global_lock();
  200.  
  201.    if( !smb_shm_header_p->consistent)
  202.    {
  203.       DEBUG(0,("ERROR smb_shm_alloc : shmem not consistent\n"));
  204.       smb_shm_global_unlock();
  205.       return 0;
  206.    }
  207.    
  208.    
  209.    /* calculate    the number of cells */
  210.    num_cells = (size + CellSize -1) / CellSize;
  211.  
  212.    /* set start    of scan */
  213.    prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
  214.    scanner_p =    prev_p ;
  215.    
  216.    /* scan the free list to find a matching free space */
  217.    while ( ( scanner_p != EOList_Addr ) && ( scanner_p->size < num_cells ) )
  218.    {
  219.       prev_p = scanner_p;
  220.       scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next);
  221.    }
  222.    
  223.    /* at this point scanner point to a block header or to the end of the list */
  224.    if ( scanner_p == EOList_Addr )    
  225.    {
  226.       DEBUG(0,("ERROR smb_shm_alloc : alloc of %d bytes failed, no free space found\n",size));
  227.       smb_shm_global_unlock();
  228.       return (0);
  229.    }
  230.    
  231.    /* going to modify shared mem */
  232.    smb_shm_header_p->consistent = False;
  233.    
  234.    /* if we found a good one : scanner == the good one */
  235.    if ( scanner_p->size <= num_cells + 2 )
  236.    {
  237.       /* there is no use in making a new one, it will be too small anyway 
  238.       *     we will link out scanner
  239.       */
  240.       if ( prev_p == scanner_p )
  241.       {
  242.      smb_shm_header_p->first_free_off = scanner_p->next ;
  243.       }
  244.       else
  245.       {
  246.      prev_p->next = scanner_p->next ;
  247.       }
  248.       smb_shm_header_p->statistics.cells_free -= scanner_p->size;
  249.       smb_shm_header_p->statistics.cells_used += scanner_p->size;
  250.    }
  251.    else
  252.    {
  253.       /* Make a new one */
  254.       new_p = scanner_p + 1 + num_cells;
  255.       new_p->size = scanner_p->size - num_cells - 1;
  256.       new_p->next = scanner_p->next;
  257.       scanner_p->size = num_cells;
  258.       scanner_p->next = smb_shm_addr2offset(new_p);
  259.       
  260.       if ( prev_p    != scanner_p )
  261.       {
  262.      prev_p->next       = smb_shm_addr2offset(new_p)  ;
  263.       }
  264.       else
  265.       {
  266.      smb_shm_header_p->first_free_off = smb_shm_addr2offset(new_p)  ;
  267.       }
  268.       smb_shm_header_p->statistics.cells_free -= num_cells+1;
  269.       smb_shm_header_p->statistics.cells_used += num_cells;
  270.       smb_shm_header_p->statistics.cells_system += 1;
  271.    }
  272.  
  273.    result_offset = smb_shm_addr2offset( &(scanner_p[1]) );
  274.    scanner_p->next =    SMB_SHM_NOT_FREE_OFF ;
  275.  
  276.    /* end modification of shared mem */
  277.    smb_shm_header_p->consistent = True;
  278.  
  279.    DEBUG(6,("smb_shm_alloc : request for %d bytes, allocated %d bytes at offset %d\n",size,scanner_p->size*CellSize,result_offset ));
  280.  
  281.    smb_shm_global_unlock();
  282.    return ( result_offset );
  283. }   
  284.  
  285.  
  286.  
  287.  
  288. /* 
  289.  * Function to create the hash table for the share mode entries. Called
  290.  * when smb shared memory is global locked.
  291.  */
  292. static BOOL smb_shm_create_hash_table( unsigned int size )
  293. {
  294.   size *= sizeof(int);
  295.  
  296.   smb_shm_global_lock();
  297.   smb_shm_header_p->userdef_off = smb_shm_alloc( size );
  298.  
  299.   if(smb_shm_header_p->userdef_off == 0)
  300.     {
  301.       DEBUG(0,("smb_shm_create_hash_table: Failed to create hash table of size %d\n",size));
  302.       smb_shm_global_unlock();
  303.       return False;
  304.     }
  305.  
  306.   /* Clear hash buckets. */
  307.   memset( smb_shm_offset2addr(smb_shm_header_p->userdef_off), '\0', size);
  308.   smb_shm_global_unlock();
  309.   return True;
  310. }
  311.  
  312. static BOOL smb_shm_register_process(char *processreg_file, pid_t pid, BOOL *other_processes)
  313. {
  314.    int smb_shm_processes_fd = -1;
  315.    int nb_read;
  316.    pid_t other_pid;
  317.    int seek_back = -((int)sizeof(other_pid));
  318.    int free_slot = -1;
  319.    int erased_slot;   
  320.    
  321.    smb_shm_processes_fd = open(processreg_file, 
  322.                    read_only?O_RDONLY:(O_RDWR|O_CREAT), 
  323.                    SHM_FILE_MODE);
  324.  
  325.    if ( smb_shm_processes_fd < 0 )
  326.    {
  327.       DEBUG(0,("ERROR smb_shm_register_process : processreg_file open failed with code %s\n",strerror(errno)));
  328.       return False;
  329.    }
  330.    
  331.    *other_processes = False;
  332.    
  333.    while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
  334.    {
  335.       if(other_pid)
  336.       {
  337.      if(process_exists(other_pid))
  338.         *other_processes = True;
  339.      else
  340.      {
  341.         /* erase old pid */
  342.             DEBUG(5,("smb_shm_register_process : erasing stale record for pid %d (seek_back = %d)\n",
  343.                       other_pid, seek_back));
  344.         other_pid = (pid_t)0;
  345.         erased_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
  346.         write(smb_shm_processes_fd, &other_pid, sizeof(other_pid));
  347.         if(free_slot < 0)
  348.            free_slot = erased_slot;
  349.      }
  350.       }
  351.       else 
  352.      if(free_slot < 0)
  353.         free_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
  354.    }
  355.    if (nb_read < 0)
  356.    {
  357.       DEBUG(0,("ERROR smb_shm_register_process : processreg_file read failed with code %s\n",strerror(errno)));
  358.       close(smb_shm_processes_fd);
  359.       return False;
  360.    }
  361.    
  362.    if(free_slot < 0)
  363.       free_slot = lseek(smb_shm_processes_fd, 0, SEEK_END);
  364.  
  365.    DEBUG(5,("smb_shm_register_process : writing record for pid %d at offset %d\n",pid,free_slot));
  366.    lseek(smb_shm_processes_fd, free_slot, SEEK_SET);
  367.    if(write(smb_shm_processes_fd, &pid, sizeof(pid)) < 0)
  368.    {
  369.       DEBUG(0,("ERROR smb_shm_register_process : processreg_file write failed with code %s\n",strerror(errno)));
  370.       close(smb_shm_processes_fd);
  371.       return False;
  372.    }
  373.  
  374.    close(smb_shm_processes_fd);
  375.  
  376.    return True;
  377. }
  378.  
  379. static BOOL smb_shm_unregister_process(char *processreg_file, pid_t pid)
  380. {
  381.    int smb_shm_processes_fd = -1;
  382.    int nb_read;
  383.    pid_t other_pid;
  384.    int seek_back = -((int)sizeof(other_pid));
  385.    int erased_slot;
  386.    BOOL found = False;
  387.    
  388.    
  389.    smb_shm_processes_fd = open(processreg_file, O_RDWR);
  390.    if ( smb_shm_processes_fd < 0 )
  391.    {
  392.       DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file open failed with code %s\n",strerror(errno)));
  393.       return False;
  394.    }
  395.    
  396.    while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
  397.    {
  398.       DEBUG(5,("smb_shm_unregister_process : read record for pid %d\n",other_pid));
  399.       if(other_pid == pid)
  400.       {
  401.      /* erase pid */
  402.          DEBUG(5,("smb_shm_unregister_process : erasing record for pid %d (seek_val = %d)\n",
  403.                      other_pid, seek_back));
  404.      other_pid = (pid_t)0;
  405.      erased_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
  406.      if(write(smb_shm_processes_fd, &other_pid, sizeof(other_pid)) < 0)
  407.      {
  408.         DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file write failed with code %s\n",strerror(errno)));
  409.         close(smb_shm_processes_fd);
  410.         return False;
  411.      }
  412.      
  413.      found = True;
  414.      break;
  415.       }
  416.    }
  417.    if (nb_read < 0)
  418.    {
  419.       DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file read failed with code %s\n",strerror(errno)));
  420.       close(smb_shm_processes_fd);
  421.       return False;
  422.    }
  423.    
  424.    if(!found)
  425.    {
  426.       DEBUG(0,("ERROR smb_shm_unregister_process : couldn't find pid %d in file %s\n",pid,processreg_file));
  427.       close(smb_shm_processes_fd);
  428.       return False;
  429.    }
  430.       
  431.    
  432.    close(smb_shm_processes_fd);
  433.  
  434.    return True;
  435. }
  436.  
  437.  
  438. static BOOL smb_shm_validate_header(int size)
  439. {
  440.    if( !smb_shm_header_p )
  441.    {
  442.       /* not mapped yet */
  443.       DEBUG(0,("ERROR smb_shm_validate_header : shmem not mapped\n"));
  444.       return False;
  445.    }
  446.    
  447.    if(smb_shm_header_p->smb_shm_magic != SMB_SHM_MAGIC)
  448.    {
  449.       DEBUG(0,("ERROR smb_shm_validate_header : bad magic\n"));
  450.       return False;
  451.    }
  452.    if(smb_shm_header_p->smb_shm_version != SMB_SHM_VERSION)
  453.    {
  454.       DEBUG(0,("ERROR smb_shm_validate_header : bad version %X\n",smb_shm_header_p->smb_shm_version));
  455.       return False;
  456.    }
  457.    
  458.    if(smb_shm_header_p->total_size != size)
  459.    {
  460.       DEBUG(0,("ERROR smb_shm_validate_header : shmem size mismatch (old = %d, new = %d)\n",smb_shm_header_p->total_size,size));
  461.       return False;
  462.    }
  463.  
  464.    if(!smb_shm_header_p->consistent)
  465.    {
  466.       DEBUG(0,("ERROR smb_shm_validate_header : shmem not consistent\n"));
  467.       return False;
  468.    }
  469.    return True;
  470. }
  471.  
  472. static BOOL smb_shm_initialize(int size)
  473. {
  474.    struct SmbShmBlockDesc * first_free_block_p;
  475.    
  476.    DEBUG(5,("smb_shm_initialize : initializing shmem file of size %d\n",size));
  477.    
  478.    if( !smb_shm_header_p )
  479.    {
  480.       /* not mapped yet */
  481.       DEBUG(0,("ERROR smb_shm_initialize : shmem not mapped\n"));
  482.       return False;
  483.    }
  484.    
  485.    smb_shm_header_p->smb_shm_magic = SMB_SHM_MAGIC;
  486.    smb_shm_header_p->smb_shm_version = SMB_SHM_VERSION;
  487.    smb_shm_header_p->total_size = size;
  488.    smb_shm_header_p->first_free_off = AlignedHeaderSize;
  489.    smb_shm_header_p->userdef_off = 0;
  490.    
  491.    first_free_block_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
  492.    first_free_block_p->next = EOList_Off;
  493.    first_free_block_p->size = ( size - AlignedHeaderSize - CellSize ) / CellSize ;
  494.    
  495.    smb_shm_header_p->statistics.cells_free = first_free_block_p->size;
  496.    smb_shm_header_p->statistics.cells_used = 0;
  497.    smb_shm_header_p->statistics.cells_system = 1;
  498.    
  499.    smb_shm_header_p->consistent = True;
  500.    
  501.    smb_shm_initialize_called = True;
  502.  
  503.    return True;
  504. }
  505.    
  506. static void smb_shm_solve_neighbors(struct SmbShmBlockDesc *head_p )
  507. {
  508.    struct SmbShmBlockDesc *next_p;
  509.    
  510.    /* Check if head_p and head_p->next are neighbors and if so join them */
  511.    if ( head_p == EOList_Addr ) return ;
  512.    if ( head_p->next == EOList_Off ) return ;
  513.    
  514.    next_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(head_p->next);
  515.    if ( ( head_p + head_p->size + 1 ) == next_p)
  516.    {
  517.       head_p->size += next_p->size +1 ;    /* adapt size */
  518.       head_p->next = next_p->next      ; /* link out */
  519.       
  520.       smb_shm_header_p->statistics.cells_free += 1;
  521.       smb_shm_header_p->statistics.cells_system -= 1;
  522.    }
  523. }
  524.  
  525.  
  526.  
  527. static BOOL smb_shm_close( void )
  528. {
  529.    
  530.    if(smb_shm_initialize_called == False)
  531.      return True;
  532.  
  533.    DEBUG(5,("smb_shm_close\n"));
  534.    if(smb_shm_times_locked > 0)
  535.       DEBUG(0,("WARNING smb_shm_close : shmem was still locked %d times\n",smb_shm_times_locked));;
  536.    if ((smb_shm_header_p != NULL) && 
  537.               (munmap((caddr_t)smb_shm_header_p, smb_shm_header_p->total_size) < 0))
  538.    {
  539.       DEBUG(0,("ERROR smb_shm_close : munmap failed with code %s\n",strerror(errno)));
  540.    }
  541.  
  542.    smb_shm_global_lock();
  543.    DEBUG(5,("calling smb_shm_unregister_process(%s, %d)\n", smb_shm_processreg_name, getpid()));
  544.    smb_shm_unregister_process(smb_shm_processreg_name, getpid());
  545.    smb_shm_global_unlock();
  546.    
  547.    close(smb_shm_fd);
  548.    
  549.    smb_shm_fd = -1;
  550.    smb_shm_processreg_name[0] = '\0';
  551.  
  552.    smb_shm_header_p = (struct SmbShmHeader *)0;
  553.    smb_shm_times_locked = 0;
  554.    
  555.    return True;
  556. }
  557.  
  558.  
  559. static BOOL smb_shm_free(int offset)
  560. {
  561.    struct SmbShmBlockDesc *header_p  ; /*    pointer    to header of block to free */
  562.    struct SmbShmBlockDesc *scanner_p ; /*    used to    scan the list               */
  563.    struct SmbShmBlockDesc *prev_p       ; /*    holds previous in the list           */
  564.    
  565.    if( !smb_shm_header_p )
  566.    {
  567.       /* not mapped yet */
  568.       DEBUG(0,("ERROR smb_shm_free : shmem not mapped\n"));
  569.       return False;
  570.    }
  571.    
  572.    smb_shm_global_lock();
  573.  
  574.    if( !smb_shm_header_p->consistent)
  575.    {
  576.       DEBUG(0,("ERROR smb_shm_free : shmem not consistent\n"));
  577.       smb_shm_global_unlock();
  578.       return False;
  579.    }
  580.    
  581.    header_p = (    (struct SmbShmBlockDesc *)smb_shm_offset2addr(offset) - 1); /* make pointer to header of block */
  582.  
  583.    if (header_p->next != SMB_SHM_NOT_FREE_OFF)
  584.    {
  585.       DEBUG(0,("ERROR smb_shm_free : bad offset (%d)\n",offset));
  586.       smb_shm_global_unlock();
  587.       return False;
  588.    }
  589.    
  590.    /* find a place in the free_list to put the header in */
  591.    
  592.    /* set scanner and previous pointer to start of list */
  593.    prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
  594.    scanner_p = prev_p ;
  595.    
  596.    while ( ( scanner_p != EOList_Addr) && (scanner_p < header_p) ) /* while we didn't scan past its position */
  597.    {
  598.       prev_p = scanner_p ;
  599.       scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next);
  600.    }
  601.    
  602.    smb_shm_header_p->consistent = False;
  603.    
  604.    DEBUG(6,("smb_shm_free : freeing %d bytes at offset %d\n",header_p->size*CellSize,offset));
  605.  
  606.    if ( scanner_p == prev_p )
  607.    {
  608.       smb_shm_header_p->statistics.cells_free += header_p->size;
  609.       smb_shm_header_p->statistics.cells_used -= header_p->size;
  610.  
  611.       /* we must free it at the beginning of the list */
  612.       smb_shm_header_p->first_free_off = smb_shm_addr2offset(header_p);                         /*    set    the free_list_pointer to this block_header */
  613.  
  614.       /* scanner is the one that was first in the list */
  615.       header_p->next = smb_shm_addr2offset(scanner_p);
  616.       smb_shm_solve_neighbors( header_p ); /* if neighbors then link them */
  617.       
  618.       smb_shm_header_p->consistent = True;
  619.       smb_shm_global_unlock();
  620.       return True;
  621.    } 
  622.    else
  623.    {
  624.       smb_shm_header_p->statistics.cells_free += header_p->size;
  625.       smb_shm_header_p->statistics.cells_used -= header_p->size;
  626.  
  627.       prev_p->next = smb_shm_addr2offset(header_p);
  628.       header_p->next = smb_shm_addr2offset(scanner_p);
  629.       smb_shm_solve_neighbors(header_p) ;
  630.       smb_shm_solve_neighbors(prev_p) ;
  631.  
  632.       smb_shm_header_p->consistent = True;
  633.       smb_shm_global_unlock();
  634.       return True;
  635.    }
  636. }
  637.  
  638. static int smb_shm_get_userdef_off(void)
  639. {
  640.    if (!smb_shm_header_p)
  641.       return 0;
  642.    else
  643.       return smb_shm_header_p->userdef_off;
  644. }
  645.  
  646. /*******************************************************************
  647.   Lock a particular hash bucket entry.
  648.   ******************************************************************/
  649. static BOOL smb_shm_lock_hash_entry( unsigned int entry)
  650. {
  651.   int start = (smb_shm_header_p->userdef_off + (entry * sizeof(int)));
  652.  
  653.   if (smb_shm_fd < 0)
  654.     {
  655.       DEBUG(0,("ERROR smb_shm_lock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
  656.       return False;
  657.     }
  658.  
  659.   /* Do an exclusive wait lock on the 4 byte region mapping into this entry  */
  660.   if (fcntl_lock(smb_shm_fd, F_SETLKW, start, sizeof(int), F_WRLCK) == False)
  661.     {
  662.       DEBUG(0,("ERROR smb_shm_lock_hash_entry : fcntl_lock failed with code %s\n",strerror(errno)));
  663.       return False;
  664.     }
  665.   
  666.   DEBUG(9,("smb_shm_lock_hash_entry: locked hash bucket %d\n", entry)); 
  667.   return True;
  668. }
  669.  
  670. /*******************************************************************
  671.   Unlock a particular hash bucket entry.
  672.   ******************************************************************/
  673. static BOOL smb_shm_unlock_hash_entry( unsigned int entry )
  674. {
  675.   int start = (smb_shm_header_p->userdef_off + (entry * sizeof(int)));
  676.  
  677.   if (smb_shm_fd < 0)
  678.     {
  679.       DEBUG(0,("ERROR smb_shm_unlock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
  680.       return False;
  681.     }
  682.    
  683.   /* Do a wait lock on the 4 byte region mapping into this entry  */
  684.   if (fcntl_lock(smb_shm_fd, F_SETLKW, start, sizeof(int), F_UNLCK) == False)
  685.     {
  686.       DEBUG(0,("ERROR smb_shm_unlock_hash_entry : fcntl_lock failed with code %s\n",strerror(errno)));
  687.       return False;
  688.     }
  689.   
  690.   DEBUG(9,("smb_shm_unlock_hash_entry: unlocked hash bucket %d\n", entry)); 
  691.   return True;
  692. }
  693.  
  694. /*******************************************************************
  695.   Gather statistics on shared memory usage.
  696.   ******************************************************************/
  697. static BOOL smb_shm_get_usage(int *bytes_free,
  698.            int *bytes_used,
  699.            int *bytes_overhead)
  700. {
  701.    if( !smb_shm_header_p )
  702.    {
  703.       /* not mapped yet */
  704.       DEBUG(0,("ERROR smb_shm_free : shmem not mapped\n"));
  705.       return False;
  706.    }
  707.    *bytes_free = smb_shm_header_p->statistics.cells_free * CellSize;
  708.    *bytes_used = smb_shm_header_p->statistics.cells_used * CellSize;
  709.    *bytes_overhead = smb_shm_header_p->statistics.cells_system * CellSize + AlignedHeaderSize;
  710.    
  711.    return True;
  712. }
  713.  
  714. /*******************************************************************
  715. hash a number into a hash_entry
  716.   ******************************************************************/
  717. static unsigned smb_shm_hash_size(void)
  718. {
  719.     return SHMEM_HASH_SIZE;
  720. }
  721.  
  722. static struct shmem_ops shmops = {
  723.     smb_shm_close,
  724.     smb_shm_alloc,
  725.     smb_shm_free,
  726.     smb_shm_get_userdef_off,
  727.     smb_shm_offset2addr,
  728.     smb_shm_addr2offset,
  729.     smb_shm_lock_hash_entry,
  730.     smb_shm_unlock_hash_entry,
  731.     smb_shm_get_usage,
  732.     smb_shm_hash_size,
  733. };
  734.  
  735. /*******************************************************************
  736.   open the shared memory
  737.   ******************************************************************/
  738. struct shmem_ops *smb_shm_open(int ronly)
  739. {
  740.     pstring file_name;
  741.     int filesize;
  742.     BOOL created_new = False;
  743.     BOOL other_processes = True;
  744.     int size = lp_shmem_size();
  745.  
  746.     read_only = ronly;
  747.  
  748.     pstrcpy(file_name,lp_lockdir());
  749.     if (!directory_exist(file_name,NULL)) {
  750.         if (read_only) return NULL;
  751.         mkdir(file_name,0755);
  752.     }
  753.     trim_string(file_name,"","/");
  754.     if (!*file_name) return(False);
  755.     pstrcat(file_name, "/SHARE_MEM_FILE");
  756.    
  757.    DEBUG(5,("smb_shm_open : using shmem file %s to be of size %d\n",file_name,size));
  758.  
  759.    smb_shm_fd = open(file_name, read_only?O_RDONLY:(O_RDWR|O_CREAT),
  760.              SHM_FILE_MODE);
  761.  
  762.    if ( smb_shm_fd < 0 )
  763.    {
  764.       DEBUG(0,("ERROR smb_shm_open : open failed with code %s\n",strerror(errno)));
  765.       return NULL;
  766.    }
  767.    
  768.    if (!smb_shm_global_lock())
  769.    {
  770.       DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_global_lock\n"));
  771.       return NULL;
  772.    }
  773.    
  774.    if( (filesize = lseek(smb_shm_fd, 0, SEEK_END)) < 0)
  775.    {
  776.       DEBUG(0,("ERROR smb_shm_open : lseek failed with code %s\n",strerror(errno)));
  777.       smb_shm_global_unlock();
  778.       close(smb_shm_fd);
  779.       return NULL;
  780.    }
  781.  
  782.    /* return the file offset to 0 to save on later seeks */
  783.    lseek(smb_shm_fd,0,SEEK_SET);
  784.  
  785.    if (filesize == 0)
  786.    {
  787.       /* we just created a new one */
  788.       created_new = True;
  789.    }
  790.    
  791.    /* to find out if some other process is already mapping the file,
  792.       we use a registration file containing the processids of the file mapping processes
  793.       */
  794.  
  795.    /* construct processreg file name */
  796.    pstrcpy(smb_shm_processreg_name, file_name);
  797.    pstrcat(smb_shm_processreg_name, ".processes");
  798.  
  799.    if (!read_only && 
  800.        !smb_shm_register_process(smb_shm_processreg_name, getpid(), &other_processes))
  801.    {
  802.       smb_shm_global_unlock();
  803.       close(smb_shm_fd);
  804.       return NULL;
  805.    }
  806.  
  807.    if (!read_only && (created_new || !other_processes))
  808.    {
  809.       /* we just created a new one, or are the first opener, lets set it size */
  810.       if( ftruncate(smb_shm_fd, size) <0)
  811.       {
  812.          DEBUG(0,("ERROR smb_shm_open : ftruncate failed with code %s\n",strerror(errno)));
  813.      smb_shm_unregister_process(smb_shm_processreg_name, getpid());
  814.      smb_shm_global_unlock();
  815.      close(smb_shm_fd);
  816.      return NULL;
  817.       }
  818.  
  819.       /* paranoia */
  820.       lseek(smb_shm_fd,0,SEEK_SET);
  821.  
  822.       filesize = size;
  823.    }
  824.    
  825.    if (size != filesize )
  826.    {
  827.       /* the existing file has a different size and we are not the first opener.
  828.      Since another process is still using it, we will use the file size */
  829.       DEBUG(0,("WARNING smb_shm_open : filesize (%d) != expected size (%d), using filesize\n",filesize,size));
  830.       size = filesize;
  831.    }
  832.    
  833.    smb_shm_header_p = (struct SmbShmHeader *)mmap(NULL, size, 
  834.                           read_only?PROT_READ:
  835.                           (PROT_READ | PROT_WRITE), 
  836.                           MAP_FILE | MAP_SHARED, 
  837.                           smb_shm_fd, 0);
  838.    /* WARNING, smb_shm_header_p can be different for different processes mapping the same file ! */
  839.    if (smb_shm_header_p  == (struct SmbShmHeader *)(-1))
  840.    {
  841.       DEBUG(0,("ERROR smb_shm_open : mmap failed with code %s\n",strerror(errno)));
  842.       smb_shm_unregister_process(smb_shm_processreg_name, getpid());
  843.       smb_shm_global_unlock();
  844.       close(smb_shm_fd);
  845.       return NULL;
  846.    }      
  847.    
  848.       
  849.    if (!read_only && (created_new || !other_processes))
  850.    {
  851.       smb_shm_initialize(size);
  852.       /* Create the hash buckets for the share file entries. */
  853.       smb_shm_create_hash_table(SHMEM_HASH_SIZE);
  854.    }
  855.    else if (!smb_shm_validate_header(size) )
  856.    {
  857.       /* existing file is corrupt, samba admin should remove it by hand */
  858.       DEBUG(0,("ERROR smb_shm_open : corrupt shared mem file, remove it manually\n"));
  859.       munmap((caddr_t)smb_shm_header_p, size);
  860.       smb_shm_unregister_process(smb_shm_processreg_name, getpid());
  861.       smb_shm_global_unlock();
  862.       close(smb_shm_fd);
  863.       return NULL;
  864.    }
  865.    
  866.    smb_shm_global_unlock();
  867.    return &shmops;
  868. }
  869.  
  870.  
  871. #else /* FAST_SHARE_MODES */
  872.  int shmem_dummy_procedure(void)
  873. {return 0;}
  874. #endif /* FAST_SHARE_MODES */
  875.